package course

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/elastic/go-elasticsearch/v7/esapi"
	"github.com/elastic/go-elasticsearch/v7/esutil"
	"math"
	"net/http"
	"time"
	"yangming-college/common/util"

	"yangming-college/app/speciality/cmd/v1/api/internal/svc"
	"yangming-college/app/speciality/cmd/v1/api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type SelfCourseListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewSelfCourseListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SelfCourseListLogic {
	return &SelfCourseListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *SelfCourseListLogic) SelfCourseList(uid int64, paginator *util.Paginator, req *types.ReqSlefList) (resp *types.RepData, err error) {

	// Build the Elasticsearch query
	query := map[string]interface{}{
		"query": map[string]interface{}{
			"match": map[string]interface{}{
				"uid": uid,
			},
		},
		"from": paginator.Offset(),
		"size": paginator.PerPage(),
		"sort": []map[string]interface{}{
			{"updated": map[string]interface{}{"order": "desc"}},
		},
	}

	// Prepare the Search request
	reqSearch := esapi.SearchRequest{
		Index: []string{"course"},
		Body:  esutil.NewJSONReader(query),
	}

	// Execute the Search request
	resSearch, err := reqSearch.Do(context.Background(), l.svcCtx.ESClinet) // Replace with your Elasticsearch client
	if err != nil {
		return nil, err
	}
	defer resSearch.Body.Close()

	// Check the response status
	if resSearch.StatusCode != http.StatusOK {
		return nil, errors.New("Elasticsearch request failed")
	}

	// Decode the response body
	courses := make([]types.Course, 0)
	var respData types.RepData
	var result map[string]interface{}
	if err := json.NewDecoder(resSearch.Body).Decode(&result); err != nil {
		return nil, err
	}

	// Extract hits information
	hits, ok := result["hits"].(map[string]interface{})
	if !ok {
		return nil, errors.New("Failed to extract hits information")
	}

	if hitsArray, ok := hits["hits"].([]interface{}); ok {
		for _, hit := range hitsArray {
			if source, ok := hit.(map[string]interface{})["_source"].(map[string]interface{}); ok {
				var course types.Course
				// Encode the nested map into JSON
				sourceJSON, err := json.Marshal(source)
				if err != nil {
					return nil, err
				}

				// Decode the JSON into the Course struct
				if err := json.Unmarshal(sourceJSON, &course); err != nil {
					return nil, err
				}
				course.Id = hit.(map[string]interface{})["_id"].(string)
				updatedTime, err := time.Parse(time.RFC3339Nano, course.Updated)
				if err != nil {
					fmt.Println("Error parsing updated time:", err)
					return &respData, err
				}
				course.Updated = updatedTime.Format("2006-01-02 15:04:05")
				courses = append(courses, course)
			}
		}
	}

	total, _ := hits["total"].(map[string]interface{})["value"].(float64)

	// Calculate total pages based on the page size
	totalPages := int(math.Ceil(total / float64(req.Size)))

	respData.Data = map[string]interface{}{
		"courses":    courses,
		"total":      int(total),
		"total_page": totalPages,
	}
	return &respData, nil
}
